import ReactDOM from 'react-dom';
import React from 'react';
import { Modal } from 'antd';
import { ModalProps, ModalFuncProps } from 'antd/lib/modal';
import cn from 'classnames';

interface ConfigProps {
  content?: React.ReactNode;
  request?: (...args: any[]) => Promise<any>;
  onError?: (...args: any[]) => void;
}

interface ModalRes {
  result: boolean;
  destory?: () => void;
  setConfirmLoading?: (loading: boolean, cb?: any) => void;
  values?: any; // 有接口请求，会将接口响应数据返回，否则返回表单数据
}

interface SyncModalProps {
  show(config: ConfigProps & ModalProps): Promise<ModalRes>;
  confirm: (config: ModalFuncProps) => Promise<ModalRes>;
  error: (config: ModalFuncProps) => Promise<ModalRes>;
  success: (config: ModalFuncProps) => Promise<ModalRes>;
  info: (config: ModalFuncProps) => Promise<ModalRes>;
  warn: (config: ModalFuncProps) => Promise<ModalRes>;
}

// @ts-ignore
const ASyncModal: SyncModalProps = {
  show(config: ConfigProps & ModalProps): Promise<ModalRes> {
    const { content, className, request, onError, ...props } = config;
    const resultFn: any = {};
    let modal;
    let formRef;

    const el = document.createElement('div');
    document.body.append(el);

    const getFormRef = ref => {
      formRef = ref;
    };

    const setLoading = loading => {
      modal = React.cloneElement(modal, {
        ...modal.props,
        confirmLoading: loading,
      });
      render(modal);
    };

    const setFormPannelLoading = loading => {
      modal = (
        <Modal
          {...props}
          visible
          onOk={onOk}
          onCancel={onCancel}
          maskClosable={false}
          className={cn('com-scroll-modal', className)}
        >
          <Com destory={destory} onFinish={onFinish} ref={formRef} loading={loading} />
        </Modal>
      );
      render(modal);
    };

    const render = (renderNode: React.ReactNode) => {
      // @ts-ignore
      ReactDOM.render(renderNode, el);
    };

    const destory = () => {
      ReactDOM.unmountComponentAtNode(el);
      el.remove();
    };

    const onOk = async () => {
      if (!formRef) return;
      try {
        const values = await formRef.validateFields();
        if (request) {
          setLoading(true);
          const data = await request(values);
          resultFn.resolve({ result: true, values: data });
        } else {
          resultFn.resolve({ result: true, values });
        }
        destory();
      } catch (error) {
        setLoading(false);
        if (!error.errorFields) {
          // 只抛出request error
          onError && onError(error);
        }
      }
    };

    const onCancel = () => {
      resultFn.resolve({ result: false });
      destory();
    };

    const onFinish = async values => {
      try {
        if (request) {
          setFormPannelLoading(true);
          const data = await request(values);
          resultFn.resolve({ result: true, values: data });
        } else {
          resultFn.resolve({ result: true, values });
        }
        destory();
      } catch (error) {
        setFormPannelLoading(false);
        if (!error.errorFields) {
          // 只抛出request error
          onError && onError(error);
        }
      }
    };

    const Com = typeof content === 'function' ? content : () => content;

    modal = (
      <Modal
        {...props}
        visible
        onOk={onOk}
        onCancel={onCancel}
        maskClosable={false}
        className={cn('com-scroll-modal', className)}
      >
        <Com destory={destory} onFinish={onFinish} getFormRef={getFormRef} />
      </Modal>
    );

    render(modal);

    return new Promise(resolve => {
      resultFn.resolve = resolve;
    });
  },
};

export default ASyncModal;

['confirm', 'error', 'info', 'success', 'warn'].forEach((method: string) => {
  ASyncModal[method] = (config: ModalFuncProps): Promise<ModalRes> => {
    return new Promise(resolve => {
      const modal = Modal[method]({
        ...config,
        onOk: (close: any) => {
          resolve({ result: true, destory: close, setConfirmLoading });
        },
        onCancel: () => {
          resolve({ result: false });
        },
      });

      function setConfirmLoading(loading: boolean) {
        modal.update({ okButtonProps: { loading } });
      }
    });
  };
});
